#define F_CPU 8000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>

//Global variables for the timer and the main
volatile int globalV = 0;	//Output value for DAC
volatile int state = 0;	//Phase of the sine wave
volatile int t = 0;	//Number of ticks that have occurred since the last transition
volatile int v = 0;	//Value to the DAC before it has been transformed
volatile int delta = 20;	//When the timer interrupts the number of ticks to send.

//This is a table to look up the values for the inverse of the sine for Pi/2 degrees.
static const int sin_table[] PROGMEM =
{
	40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,42,42,
	42,42,42,42,42,43,43,43,43,43,44,44,44,44,45,45,45,46,46,46,46,47,47,48,48,48,49,49,50,50,51,51,
	52,52,53,54,54,55,56,57,58,58,59,61,62,63,64,65,67,69,70,72,74,77,79,82,85,89,94,99,105,112,122,135,
	152,180,235
};

//This function waits for the twi to finish.
int twi_wait(){
	while(!(TWCR & (1<<TWINT)));
	return (TWSR&0xF8);
}

//This functions starts the initialize of twi.
void twi_init(){
	TWBR = 0;	//sets the max speed
	TWSR = 0;
}

//This function sends data to the twi.
int twi_send(int data){
	TWDR = data; //Set the data.
	TWCR = (1<<TWINT) | (1<<TWEN); //Enable TWI.
	return twi_wait(); //Wait for TWI to finish.
}

//This function starts the trans for the mcp4725.
void mcp4725_start(){
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
	if(twi_wait()!=0x08) return;
	if(twi_send(0xC0)!=0x18) return;
}

//Sets the ms and ls values for the mcp4725.
void mcp4725_set(int ms, int ls){
	if(twi_send(ms&0xF)!=0x28){
		return;
	}
	if(twi_send(ls)!=0x28){
		return;
	}
}

void adc_setup(){
	//data will be L-Justified, PC0 for analog reading, 5V external voltage ref with 10uf cap
	ADMUX = (1<<REFS1) | (1<<REFS0) | (1<<ADLAR) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
	//make ADC enable and select ck/128
	ADCSRA = (1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
}

//This is the main function
int main(void){
	adc_setup();		//initialize ADC

	//enable interrupts on t1, enable OutputCompareA interrupt
	TIMSK1 = (1<<ICIE1) | (1<<OCIE1A) | (0<<TOIE1);
	sei();				//enable interrupts 
	OCR1A = 0x00FA;		//Delay time
	TCCR1A = (0<<WGM11) | (0<<WGM10);	//CTC
	TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);  

	twi_init();			//initialize TWI function
	mcp4725_start();	//start trans for the MCP4725 function
	while(1){	//Continuously output to MCP
		cli();	//Atomically read from the global DAC value.
		int y = globalV;
		mcp4725_set((int)((y>>8)&0x0F),(int)(y&0xFF));	//Write to the MCP4725.
	}
}

//Interrupt for the Timer1 ctc.
ISR(TIMER1_COMPA_vect){
	cli();
	if(!(ADCSRA&(1<<ADSC))){	//Checks if the ADC has finished
		delta = 8+(ADC>>4);	//Sets the number of ticks to increment so the frequency varies.
		ADCSRA |= 1<<ADEN;	//Starts the ADC again.
		ADMUX = 0b01000000;
		ADCSRA |= 1<<ADSC;
	}

	int d = pgm_read_word(&sin_table[(state&1)?98-v:v]);	//Read from the inverse sine and adjust it with the phase.
	if(t+delta < d && t < d-delta){
		t += delta;
	}
	else{
		t += delta;
		//Keep incrementing the states so to skip states if there is a large enough change.
		do{
			t -= d;
			v++;
			if(v >= 99){	//Updates phase only if needed.
				v = 0;
				state = (state+1)&3;
			}
			d = pgm_read_word(&sin_table[(state&1)?98-v:v]);	//Inverse the sine.
		}
		while(t > d);
		int y = v;
		switch(state){	//Transforms the output based on scale and phase.
			case 0: y += 99; break;
			case 1: y = 198-y; break;
			case 2: y = 99-y; break;
		}
		y <<= 4;
		globalV = y;
	}
	sei();
}